package com.park.microprofile.configsource;

import com.sun.deploy.util.ReflectionUtil;
import org.eclipse.microprofile.config.spi.ConfigSource;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 配置源集合
 *
 * @author Aaron
 * @date 2021/7/14 14:27
 */
public class ConfigSources implements Iterable<ConfigSource> {

    private ClassLoader classLoader;

    /**
     * 配置源集合
     */
    private final List<ConfigSource> configSources = new LinkedList<>();

    /**
     * 是否通过 SPI 加载过
     */
    private boolean isDiscoveredConfigSource = false;
    /**
     * 是否添加过默认配置
     */
    private boolean isDefaultConfigSource = false;

    public ConfigSources(ClassLoader classLoader) {
        this.classLoader = classLoader;
        // 初始化默认配置
        addDefaultConfigSource();
    }

    /**
     * 添加默认配置源
     */
    public void addDefaultConfigSource() {
        if (isDefaultConfigSource) {
            return;
        }
        addConfigSources(DefaultJavaSystemPropertiesSource.class
                , DefaultOperatingSystemEnvSource.class
                , DefaultResourceConfigSource.class);
        isDefaultConfigSource = true;
    }

    /**
     * 通过 SPI 机制加载配置源
     */
    public void addDiscoveredConfigSource() {
        if (isDiscoveredConfigSource) {
            return;
        }

        // 通过 SPI 加载配置源
        addConfigSources(ServiceLoader.load(ConfigSource.class, this.classLoader));
        isDiscoveredConfigSource = true;
    }

    /**
     * 添加单一配置源
     */
    public void addConfigSource(ConfigSource configSource) {
        addConfigSources(configSource);
    }

    public void addConfigSources(Class<? extends ConfigSource>... configSourceClasses) {
        addConfigSources(Stream.of(configSourceClasses)
                .map(this::newInstance)
                .collect(Collectors.toList()));
    }

    public void addConfigSources(ConfigSource... configSources) {
        addConfigSources(Arrays.asList(configSources));
    }

    private void addConfigSources(Iterable<ConfigSource> configSources) {
        // 添加配置源
        configSources.forEach(this.configSources::add);

        // 排序
        this.configSources.sort((Comparator.comparingInt(ConfigSource::getOrdinal)));
    }

    /**
     * 使用反射初始化配置源对象
     */
    private ConfigSource newInstance(Class<? extends ConfigSource> configSourceClass) {
        ConfigSource instance = null;
        try {
            instance = configSourceClass.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new IllegalStateException(e);
        }
        return instance;
    }


    @Override
    public Iterator<ConfigSource> iterator() {
        return configSources.iterator();
    }

    public void setClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

}
